// 使用 runtime.LockOSThread 将每个 goroutine 绑定到特定 OS 线程，并通过 cgo 调用 pthread_self 获取线程 ID，展示 goroutine 在 OS 线程上的运行情况
// 该示例依赖 CGO 和 POSIX 线程（适用于 Linux / macOS）。
// 需确保执行环境启用 CGO（默认 CGO_ENABLED=1）

package main

/*
#include <pthread.h>
#include <stdint.h>

// 返回当前 POSIX 线程 ID。pthread_t 在不同平台类型不同，统一转成 uint64_t。
static uint64_t currentThreadID() {
	return (uint64_t)pthread_self();
}
*/
import "C"

import (
	"fmt"
	"runtime"
	"sync"
	"time"
)

func main() {
	const workers = 4

	// 限制逻辑 P 数量，便于观察 goroutine 在少量线程上运行。
	prevProcs := runtime.GOMAXPROCS(workers)
	defer runtime.GOMAXPROCS(prevProcs)

	var wg sync.WaitGroup
	wg.Add(workers)

	for i := 0; i < workers; i++ {
		go func(id int) {
			defer wg.Done()

			// 将当前 goroutine 绑定到它所运行的 OS 线程，避免调度器迁移。
			runtime.LockOSThread()
			defer runtime.UnlockOSThread()

			threadID := uint64(C.currentThreadID())
			fmt.Printf("[worker-%d] 已绑定 OS 线程 ID=%d\n", id, threadID)

			for round := 1; round <= 3; round++ {
				fmt.Printf("[worker-%d] 第 %d 轮工作，仍在 OS 线程 %d 上\n", id, round, threadID)
				time.Sleep(200 * time.Millisecond) // 模拟耗时任务
			}

			fmt.Printf("[worker-%d] 完成所有工作，退出时仍绑定 OS 线程 %d\n", id, threadID)
		}(i)
	}

	wg.Wait()
	fmt.Println("所有绑定线程的 goroutine 执行完毕。")
}
